package cn.ztuo.bitrade.controller.contract;

import cn.ztuo.bitrade.annotation.AccessLog;
import cn.ztuo.bitrade.constant.AdminModule;
import cn.ztuo.bitrade.constant.BooleanEnum;
import cn.ztuo.bitrade.constant.PageModel;
import cn.ztuo.bitrade.constant.TransactionTypeEnum;
import cn.ztuo.bitrade.controller.BaseController;
import cn.ztuo.bitrade.dao.ContractOrderMapper;
import cn.ztuo.bitrade.dao.MemberDao;
import cn.ztuo.bitrade.entity.*;
import cn.ztuo.bitrade.model.screen.ContractOrderScreen;
import cn.ztuo.bitrade.service.ContractOrderDetailService;
import cn.ztuo.bitrade.service.ContractOrderService;
import cn.ztuo.bitrade.service.LocaleMessageSourceService;
import cn.ztuo.bitrade.util.DateUtil;
import cn.ztuo.bitrade.util.MessageResult;
import cn.ztuo.bitrade.util.PredicateUtils;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.BooleanExpression;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.BulkOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.util.Pair;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;

@Slf4j
@RequestMapping("/contract/contract-order")
@RestController
public class ContractOrederController extends BaseController {

    @Autowired
    private ContractOrderService contractOrderService;
    @Autowired
    private ContractOrderMapper contractOrderMapper;

    @Autowired
    private LocaleMessageSourceService messageSource;

    @Autowired
    private ContractOrderDetailService contractOrderDetailService;

    @Autowired
    private MongoTemplate mongoTemplate ;

    @Autowired
    private MemberDao memberDao ;


    @RequiresPermissions(value = {"contract:contract-order:detail"}, logical = Logical.OR)
    @PostMapping("/detail")
    @AccessLog(module = AdminModule.SYSTEM, operation = "contractOrder详情")
    public MessageResult detail(@RequestParam("id") String id) {
        List<ContractOrderDetail> one = contractOrderDetailService.findAllByOrderId(id);
        ContractOrder contractOrder = contractOrderService.findOne(id);
        if (one == null) {
            return error(messageSource.getMessage("NO_DATA"));
        }
        Map map = new HashMap();
        map.put("detail", one);
        map.put("order", contractOrder);
        return success(map);
    }
    /**
     * 合约订单查询
     *
     * @param pageModel
     * @return
     */
    @RequiresPermissions(value = {"contract:contract-order:page-query"})
    @PostMapping("page-query")
    @AccessLog(module = AdminModule.EXCHANGE, operation = "分页查找ContractOrder")
    public MessageResult pageQuery(
            PageModel pageModel,
            ContractOrderScreen screen) {
        if (pageModel.getDirection() == null && pageModel.getProperty() == null) {
            ArrayList<Sort.Direction> directions = new ArrayList<>();
            directions.add(Sort.Direction.DESC);
            pageModel.setDirection(directions);
            List<String> property = new ArrayList<>();
            property.add("listTime");
            pageModel.setProperty(property);
        }
        //获取查询条件
        Predicate predicate = getPredicate(screen);
        Page<ContractOrder> all = contractOrderService.findAll(predicate, pageModel.getPageable());
        all.getContent().forEach(contractOrder -> {
            BigDecimal tradedAmount = BigDecimal.ZERO;
            BigDecimal yingKui = BigDecimal.ZERO;
            List<ContractOrderDetail> details = contractOrderDetailService.findAllByOrderId(contractOrder.getOrderId());
            contractOrder.setDetail(details);
            for(ContractOrderDetail trade:details){
                tradedAmount = tradedAmount.add(trade.getAmount());
                yingKui = yingKui.add(trade.getYingKui());
            }
            contractOrder.setTradedAmount(tradedAmount);
            contractOrder.setYingKui(yingKui);
        });
        return success(all);
    }

    private Predicate getPredicate(ContractOrderScreen screen) {
        ArrayList<BooleanExpression> booleanExpressions = new ArrayList<>();
        QContractOrder qExchangeOrder = QContractOrder.contractOrder;
        if (screen.getOrderDirection() != null) {
            booleanExpressions.add(qExchangeOrder.direction.eq(screen.getOrderDirection()));
        }
        if (StringUtils.isNotEmpty(screen.getOrderId())) {
            booleanExpressions.add(qExchangeOrder.orderId.eq(screen.getOrderId()));
        }
        if (screen.getMemberId() != null) {
            booleanExpressions.add(qExchangeOrder.memberId.eq(screen.getMemberId()));
        }
        if (screen.getType() != null) {
            booleanExpressions.add(qExchangeOrder.type.eq(screen.getType()));
        }
        if (StringUtils.isNotBlank(screen.getCoinSymbol())) {
            booleanExpressions.add(qExchangeOrder.coinSymbol.equalsIgnoreCase(screen.getCoinSymbol()));
        }
        if (StringUtils.isNotBlank(screen.getBaseSymbol())) {
            booleanExpressions.add(qExchangeOrder.baseSymbol.equalsIgnoreCase(screen.getBaseSymbol()));
        }
        if (screen.getStatus() != null) {
            booleanExpressions.add(qExchangeOrder.status.eq(screen.getStatus()));
        }
        if (screen.getMinPrice() != null) {
            booleanExpressions.add(qExchangeOrder.price.goe(screen.getMinPrice()));
        }
        if (screen.getMaxPrice() != null) {
            booleanExpressions.add(qExchangeOrder.price.loe(screen.getMaxPrice()));
        }
        if (screen.getMinTradeAmount() != null) {
            booleanExpressions.add(qExchangeOrder.tradedAmount.goe(screen.getMinTradeAmount()));
        }
        if (screen.getMaxTradeAmount() != null) {
            booleanExpressions.add(qExchangeOrder.tradedAmount.loe(screen.getMaxTradeAmount()));
        }
        if (screen.getMinTurnOver() != null) {
            booleanExpressions.add(qExchangeOrder.turnover.goe(screen.getMinTurnOver()));
        }
        if (screen.getMaxTurnOver() != null) {
            booleanExpressions.add(qExchangeOrder.turnover.loe(screen.getMaxTurnOver()));
        }
        if (screen.getCompleted() != null) {
            /**
             * 委托订单
             */
            if (screen.getCompleted() == BooleanEnum.IS_FALSE) {
                booleanExpressions.add(qExchangeOrder.completedTime.isNull().and(qExchangeOrder.canceledTime.isNull())
                        .and(qExchangeOrder.status.eq(ContractOrderStatus.TRADING)));
            } else {
                /**
                 * 历史订单
                 */
                booleanExpressions.add(qExchangeOrder.completedTime.isNotNull().or(qExchangeOrder.canceledTime.isNotNull())
                        .or(qExchangeOrder.status.ne(ContractOrderStatus.TRADING)));
            }
        }
//        if (screen.getMarginTrade() != null) {
//            booleanExpressions.add(qExchangeOrder.marginTrade.eq(screen.getMarginTrade()));
//        } else {
//            booleanExpressions.add(qExchangeOrder.marginTrade.eq(BooleanEnum.IS_FALSE).or(qExchangeOrder.marginTrade.isNull()));
//        }
        booleanExpressions.add(qExchangeOrder.memberId.ne(0L));
        booleanExpressions.add(qExchangeOrder.memberId.ne(1L));
        return PredicateUtils.getPredicate(booleanExpressions);
    }

    @RequestMapping("updateContractDetailTypeAndUnit")
    public MessageResult updateContractDetailTypeAndUnit(){
        List<ContractOrder> orders = contractOrderService.findByStatus(ContractOrderStatus.COMPLETED);
        BulkOperations operations = mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, "order_detail_aggregation");
        List<Pair<Query, Update>> list = new ArrayList<>();

        for (ContractOrder order : orders) {
            Query query = new Query();
            query.addCriteria(Criteria.where("orderId").is(order.getOrderId()).and("_class").is("cn.ztuo.bitrade.entity.ContractOrderDetailAggregation"));
            Update update = new Update();
            update.set("type", "CONTRACT");
            update.set("unit", order.getCoinSymbol());

            Pair<Query, Update> pair = Pair.of(query, update);
            list.add(pair);
        }
        operations.updateMulti(list);
        operations.execute();
        return MessageResult.success("");
    }

    @RequestMapping("statistics")
    public MessageResult statistics() throws ParseException {
        List<Date> list = getDateList();
        String dateStr = "";
        for(Date date :list){
            dateStr = DateUtil.YYYY_MM_DD.format(date) ;
            statisticsFee(dateStr,date);
        }
        return MessageResult.success("");
    }

    private void statisticsFee(String dateStr,Date date) throws ParseException {
//        /**
//         * 合约成交(按照交易对统计)
//         */
//        List<Object[]> list1 = contractOrderMapper.getContractTurnoverSymbol();
//        ExchangeTurnoverStatistics exchangeTurnoverStatistics = new ExchangeTurnoverStatistics() ;
//        for(Object[] objects:list1){
//            exchangeTurnoverStatistics.setDate(date);
//            exchangeTurnoverStatistics.setAmount((BigDecimal)objects[5]);
//            exchangeTurnoverStatistics.setBaseSymbol((String)objects[0]);
//            exchangeTurnoverStatistics.setCoinSymbol((String)objects[1]);
//            exchangeTurnoverStatistics.setMoney((BigDecimal)objects[4]);
//            exchangeTurnoverStatistics.setNowp((BigDecimal)objects[5]);
//            exchangeTurnoverStatistics.setYear(DateUtil.getDatePart(DateUtil.strToDate((String)objects[2],DateUtil.YYYY_MM_DD), Calendar.YEAR));
//            //Calendar month 默认从0开始，方便起见 保存月份从1开始
//            exchangeTurnoverStatistics.setMonth(DateUtil.getDatePart(DateUtil.strToDate((String)objects[2],DateUtil.YYYY_MM_DD),Calendar.MONTH)+1);
//            exchangeTurnoverStatistics.setDay(DateUtil.getDatePart(DateUtil.strToDate((String)objects[2],DateUtil.YYYY_MM_DD),Calendar.DAY_OF_MONTH));
//            mongoTemplate.insert(exchangeTurnoverStatistics,"contract_turnover_statistics");
//        }
//
//        /**
//         * 合约成交额
//         */

        /**
         * 合约成交(按照交易对统计)
         */
        List<Object[]> list = contractOrderMapper.getContractTurnoverSymbol(dateStr);
        ExchangeTurnoverStatistics exchangeTurnoverStatistics = new ExchangeTurnoverStatistics() ;
        for(Object[] objects:list){
            exchangeTurnoverStatistics.setDate(DateUtil.YYYY_MM_DD.parse(dateStr));
            exchangeTurnoverStatistics.setAmount((BigDecimal)objects[5]);
            exchangeTurnoverStatistics.setBaseSymbol((String)objects[0]);
            exchangeTurnoverStatistics.setCoinSymbol((String)objects[1]);
            exchangeTurnoverStatistics.setMoney((BigDecimal)objects[4]);
            exchangeTurnoverStatistics.setNowp((BigDecimal)objects[5]);
            exchangeTurnoverStatistics.setYear(DateUtil.getDatePart(date,Calendar.YEAR));
            //Calendar month 默认从0开始，方便起见 保存月份从1开始
            exchangeTurnoverStatistics.setMonth(DateUtil.getDatePart(date,Calendar.MONTH)+1);
            exchangeTurnoverStatistics.setDay(DateUtil.getDatePart(date,Calendar.DAY_OF_MONTH));
            mongoTemplate.insert(exchangeTurnoverStatistics,"contract_turnover_statistics");
        }



        TurnoverStatistics turnoverStatistics = new TurnoverStatistics();
        turnoverStatistics.setDate(DateUtil.YYYY_MM_DD.parse(dateStr));
        turnoverStatistics.setYear(DateUtil.getDatePart(date,Calendar.YEAR));
        //Calendar month 默认从0开始，方便起见 保存月份从1开始
        turnoverStatistics.setMonth(DateUtil.getDatePart(date,Calendar.MONTH)+1);
        turnoverStatistics.setDay(DateUtil.getDatePart(date,Calendar.DAY_OF_MONTH));
//        turnoverStatistics.setFee(null);
//        List<Object[]> list6 = contractOrderMapper.getContractTurnoverBase();
//        for(Object[] objects:list6){
//            turnoverStatistics.setUnit(objects[0].toString());
//            turnoverStatistics.setDate(DateUtil.strToDate((String)objects[1],DateUtil.YYYY_MM_DD));
//            turnoverStatistics.setAmount((BigDecimal) objects[3]);
//            turnoverStatistics.setType(TransactionTypeEnum.CONTRACT_BASE);
//            mongoTemplate.insert(turnoverStatistics,"turnover_statistics");
//        }
//
//        /**
//         * 合约成交量
//         */
//        List<Object[]> list7 = contractOrderMapper.getContractTurnoverCoin();
//        for(Object[] objects:list7){
//            turnoverStatistics.setUnit(objects[0].toString());
//            turnoverStatistics.setAmount((BigDecimal) objects[3]);
//            turnoverStatistics.setType(TransactionTypeEnum.CONTRACT_COIN);
//            turnoverStatistics.setDate(DateUtil.strToDate((String)objects[1],DateUtil.YYYY_MM_DD));
//            mongoTemplate.insert(turnoverStatistics,"turnover_statistics");
//        }
//        /**
//         * 合约交易手续费
//         */
//        ProjectionOperation projectionOperation1 =  Aggregation.project("time","type","unit","fee");
//
//        Criteria operator1 = Criteria.where("coinName").ne("").andOperator(
//                Criteria.where("type").is("CONTRACT")
//        );
//        MatchOperation matchOperation1 = Aggregation.match(operator1);
//        GroupOperation groupOperation1 = Aggregation.group("unit","type").sum("fee").as("feeSum") ;
//
//        Aggregation aggregation1 = Aggregation.newAggregation(projectionOperation1, matchOperation1, groupOperation1);
//        // 执行操作
//        AggregationResults<Map> aggregationResults1 = this.mongoTemplate.aggregate(aggregation1, "order_detail_aggregation", Map.class);
//        List<Map> list8 = aggregationResults1.getMappedResults();
//        for(Map map:list8){
//            turnoverStatistics.setFee(new BigDecimal(map.get("feeSum").toString()));
//            turnoverStatistics.setAmount(null);
//            turnoverStatistics.setDate(new Date(Long.valueOf(map.get("time").toString())*1000));
//            turnoverStatistics.setUnit(map.get("unit").toString());
//            turnoverStatistics.setType(TransactionTypeEnum.CONTRACT);
//            mongoTemplate.insert(turnoverStatistics,"turnover_statistics");
//        }
        /**
         * 合约成交额
         */
        turnoverStatistics.setFee(null);
        List<Object[]> list6 = contractOrderMapper.getContractTurnoverBase(dateStr);
        for(Object[] objects:list6){
            turnoverStatistics.setUnit(objects[0].toString());
            turnoverStatistics.setAmount((BigDecimal) objects[3]);
            turnoverStatistics.setType(TransactionTypeEnum.CONTRACT_BASE);
            mongoTemplate.insert(turnoverStatistics,"turnover_statistics");
        }

        /**
         * 合约成交量
         */
        List<Object[]> list7 = contractOrderMapper.getContractTurnoverCoin(dateStr);
        for(Object[] objects:list7){
            turnoverStatistics.setUnit(objects[0].toString());
            turnoverStatistics.setAmount((BigDecimal) objects[3]);
            turnoverStatistics.setType(TransactionTypeEnum.CONTRACT_COIN);
            mongoTemplate.insert(turnoverStatistics,"turnover_statistics");
        }
        /**
         * 合约交易手续费
         */
        ProjectionOperation projectionOperation1 = Aggregation.project("time","type","unit","fee");

        Criteria operator1 = Criteria.where("coinName").ne("").andOperator(
                Criteria.where("time").gte(DateUtil.YYYY_MM_DD_MM_HH_SS.parse(dateStr+" 00:00:00").getTime()/1000),
                Criteria.where("time").lte(DateUtil.YYYY_MM_DD_MM_HH_SS.parse(dateStr+" 23:59:59").getTime()/1000),
                Criteria.where("type").is("CONTRACT")

        );

        MatchOperation matchOperation1 = Aggregation.match(operator1);

        GroupOperation groupOperation1 = Aggregation.group("unit","type").sum("fee").as("feeSum") ;

        Aggregation aggregation1 = Aggregation.newAggregation(projectionOperation1, matchOperation1, groupOperation1);
        // 执行操作
        AggregationResults<Map> aggregationResults1 = this.mongoTemplate.aggregate(aggregation1, "order_detail_aggregation", Map.class);
        List<Map> list8 = aggregationResults1.getMappedResults();
        for(Map map:list8){
            turnoverStatistics.setFee(new BigDecimal(map.get("feeSum").toString()));
            turnoverStatistics.setAmount(null);
            turnoverStatistics.setUnit(map.get("unit").toString());
            turnoverStatistics.setType(TransactionTypeEnum.CONTRACT);
            mongoTemplate.insert(turnoverStatistics,"turnover_statistics");
        }
    }
    private List<Date> getDateList() throws ParseException {
        List<Date> list = new ArrayList<>() ;

        Date date = memberDao.getStartRegistrationDate();
        String dateStr = DateUtil.YYYY_MM_DD.format(date) ;
        date = DateUtil.YYYY_MM_DD.parse(dateStr);

        Calendar calendar = Calendar.getInstance() ;
        calendar.setTime(date);
        Date endDate = DateUtil.dateAddDay(new Date(),-1) ;
        while(date.before(endDate)){
            list.add(date);
            calendar.add(Calendar.DAY_OF_MONTH,1);
            date = calendar.getTime() ;
        }
        return list;
    }
}
